package com.coffee.concurrent;


import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutorService;

/**
 * Manager of processors 处理器管理类<br>
 * Maintains the relationship between command and command processor through command code.
 *
 * @Author King.Song
 * @version $Id: ProcessorManager.java, v 0.1 Sept 6, 2015 2:49:47 PM tao Exp $
 */
@Slf4j
public class CoffeeExecutorManager {
    private static CoffeeExecutorManager processorManager = new CoffeeExecutorManager();

    @Getter
    private CoffeeDisruptorPool executorPool;

    @Getter
    private CoffeeScheduler defaultScheduler;
    /**
     * The default executor, if no executor is set for processor, this one will be used 如果没有为处理类设置线程池,则默认此线程池
     */
    @Getter
    private ExecutorService defaultExecutor;

    @Getter
    private ExecutorService slowExecutor;

    /**
     * minPoolSize(线程池的基本大小): 32
     * maxPoolSize(线程池最大大小): 512
     * queueSize(任务队列大小): 1024
     * keepAliveTime(线程活动保持时间): 60s
     */
    private int minPoolSize = ExecutorConfigManager.default_tp_min_size();

    private int minSchedulerPoolSize = ExecutorConfigManager.default_tsp_min_size();

    private int maxPoolSize = ExecutorConfigManager.default_tp_max_size();

    private int queueSize = ExecutorConfigManager.default_tp_queue_size();

    private long keepAliveTime = ExecutorConfigManager.default_tp_keepalive_time();

    private CoffeeExecutorManager() {
        defaultExecutor = ThreadPool.buildThreadPool(minPoolSize, maxPoolSize, queueSize, keepAliveTime, "coffee-def");
    }

    public static CoffeeExecutorManager getInstance() {
        if (processorManager == null) {
            synchronized (CoffeeExecutorManager.class) {
                if (processorManager == null) {
                    processorManager = new CoffeeExecutorManager();
                }
            }
        }
        return processorManager;
    }


    public CoffeeExecutorManager disruptor(int size) {
        int num = Runtime.getRuntime().availableProcessors() * size;
        num = Math.max(num, 32);
        log.info("Initialize disruptorPool size {}", num);
        executorPool = new CoffeeDisruptorPool(num, "coffee-dis");
        executorPool.start();
        return this;
    }

    //init scheduler
    public CoffeeExecutorManager scheduler(){
        this.defaultScheduler = new CoffeeScheduler(minSchedulerPoolSize);
        return this;
    }

    public CoffeeExecutorManager slowExecutor(int minPoolSize, int maxPoolSize, int queueSize){
        this.slowExecutor = ThreadPool.buildThreadPool(minPoolSize, maxPoolSize, queueSize, keepAliveTime, "coffee-slow");
        return this;
    }

    public CoffeeExecutorManager slowExecutor(){
        this.slowExecutor = ThreadPool.buildThreadPool(minPoolSize, maxPoolSize, queueSize, keepAliveTime, "coffee-slow");
        return this;
    }


    public CoffeeDisruptor getDisruptorByUserId(long userId) {
        int index = (int) (userId % executorPool.size());
        return executorPool.getByIndex(index);
    }

    public CoffeeDisruptor getDisruptor(int no) {
        return executorPool.getByBizNo(no);
    }


}